package com.ruoyi.framework.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;  // 注意：使用Spring的Value注解
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
import com.ruoyi.framework.config.properties.PermitAllUrlProperties;
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;

/**
 * spring security配置
 * 主要负责系统的访问权限控制，哪些接口需要登录，哪些接口可以匿名访问
 */
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
public class SecurityConfig
{
    // 从配置文件中读取头像访问的基础URL（对应application.yml中的file.access.url）
    @Value("${file.access.url}")
    private String avatarAccessUrl;

    /**
     * 自定义用户认证逻辑（框架默认实现，无需修改）
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 认证失败处理类（用于返回401等错误信息）
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;

    /**
     * 退出处理类（处理用户退出逻辑）
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器（验证请求中的JWT令牌）
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;

    /**
     * 跨域过滤器（处理前后端跨域请求）
     */
    @Autowired
    private CorsFilter corsFilter;

    /**
     * 允许匿名访问的地址配置（框架自带的配置类）
     */
    @Autowired
    private PermitAllUrlProperties permitAllUrl;

    /**
     * 身份验证管理器（处理用户名密码登录逻辑）
     */
    @Bean
    public AuthenticationManager authenticationManager()
    {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
        return new ProviderManager(daoAuthenticationProvider);
    }

    /**
     * 安全过滤链配置（核心配置，控制所有请求的访问权限）
     */
    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception
    {
        // 添加打印语句，确认avatarAccessUrl的实际值
        System.out.println("===== 头像访问路径配置：" + avatarAccessUrl + " =====");
        return httpSecurity
                // 1. 禁用CSRF保护（因为使用JWT令牌，不依赖session）
                .csrf(csrf -> csrf.disable())
                // 2. 禁用HTTP响应缓存（防止敏感数据缓存）
                .headers((headersCustomizer) -> {
                    headersCustomizer.cacheControl(cache -> cache.disable())  // 禁用缓存
                            .frameOptions(options -> options.sameOrigin());  // 允许同域iframe嵌套
                })
                // 3. 配置认证失败处理（当访问需要登录的接口却未登录时）
                .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
                // 4. 配置session管理（基于JWT，不需要创建session）
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 5. 核心：配置URL访问权限
                .authorizeHttpRequests((requests) -> {
                    // 5.1 先添加配置文件中定义的匿名访问地址
                    permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());

                    // 5.2 允许匿名访问的基础接口
                    requests.antMatchers("/login", "/register", "/captchaImage").permitAll()  // 登录、注册、验证码
                            // 5.3 允许匿名访问静态资源
                            .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                            // 5.4 允许匿名访问Swagger文档（开发环境用）
                            .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                            // 5.5 关键：允许匿名访问头像上传接口
                            .antMatchers("/upload").permitAll()
                            // 5.6 关键：允许匿名访问所有头像文件（根据配置的路径）
                            .antMatchers(avatarAccessUrl + "/**").permitAll()
                            // 5.7 除了上面允许的，其他所有请求都需要登录认证
                            .anyRequest().authenticated();
                })
                // 6. 配置退出登录逻辑
                .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
                // 7. 添加JWT过滤器（在用户名密码认证过滤器之前执行）
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // 8. 添加跨域过滤器（在JWT过滤器和退出过滤器之前）
                .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
                .addFilterBefore(corsFilter, LogoutFilter.class)
                // 构建配置
                .build();
    }

    /**
     * 密码加密器（使用BCrypt算法加密密码）
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
}
